#define USE_BOOST_IO_IMPL
#if !defined(USE_BOOST_IO_IMPL)
#	if defined(_WIN32) || defined(_WIN32)
#		define F_HAS_OS_API_SUPPORT
#		include "impl/windows.h"
#	endif
#endif

#if !defined(USE_BOOST_IO_IMPL)
#	if defined(__unix__) || defined(__lunix__)
#		define F_HAS_OS_API_SUPPORT
#		include "impl/lunix.h"
#	endif
#endif

#if defined(USE_BOOST_IO_IMPL)
#	define F_HAS_OS_API_SUPPORT
#	include "impl/boost_impl.hpp"
#endif

#if defined(F_HAS_OS_API_SUPPORT)
#	undef F_HAS_OS_API_SUPPORT
#else
#	error "iofile.h : OS not supported"
#endif

#include "iofile.h"

namespace commons { namespace io {

	template <class char_type>
	basic_sink_file<char_type>::basic_sink_file() 
		: impl_(NULL) 
	{ }

	template <class char_type>
	basic_sink_file<char_type>::~basic_sink_file() {
		this->close();
	}

	template <class char_type>
	basic_sink_file<char_type>::basic_sink_file(std::basic_string<char_type> const & name, open_mode mode) 
		: impl_(NULL)
	{
		this->open(name, mode);
	}

	template <class char_type>
	bool basic_sink_file<char_type>::open(std::basic_string<char_type> const & name, open_mode mode){
		if (impl_ != NULL) return false;
		impl_ = new detail::WriteDeviceImpl();
		if(!detail::source_file_impl::create<char_type>(impl_->handle(), name, detail::source_file_impl::mode(mode))) {
			delete impl_; impl_ = NULL;
			return false;
		}
		return true;
	}

	template <class char_type>
	void basic_sink_file<char_type>::close(){
		if (impl_ != NULL) {
			detail::source_file_impl::close<char_type>(impl_->handle());
			delete impl_; impl_ = NULL;
		}
	}

	template <class char_type>
	std::streamsize basic_sink_file<char_type>::write(char const * buf, std::streamsize n){
		if (impl_ != NULL && buf != NULL) 
			return detail::source_file_impl::write<char_type>(impl_->handle(), buf, n);
		return -1;
	}

	template <class char_type>
	offset_type basic_sink_file<char_type>::seek(offset_type where){
		if (impl_ != NULL)
			return detail::source_file_impl::seek<offset_type, char_type>(impl_->handle(), 
				detail::source_file_impl::offset(where)
			);
		return -1;
	}

	template <class char_type>
	offset_type basic_sink_file<char_type>::seek(seek_dir way) {
		if (impl_ != NULL) {
			switch (way) {
				case beg : 
					return detail::source_file_impl::seek_beg<offset_type, char_type>(impl_->handle());
				case end : 
					return detail::source_file_impl::seek_end<offset_type, char_type>(impl_->handle());
				case cur : 
					return detail::source_file_impl::seek_cur<offset_type, char_type>(impl_->handle());
			}
		}
		return -1;
	}

	template class basic_sink_file<char>;
	template class basic_sink_file<wchar_t>;

	template <class char_type>
	basic_source_file<char_type>::basic_source_file() 
		: impl_(NULL) 
	{ }

	template <class char_type>
	basic_source_file<char_type>::~basic_source_file() {
		this->close();
	}

	template <class char_type>
	basic_source_file<char_type>::basic_source_file(std::basic_string<char_type> const & name, open_mode mode) 
		: impl_(NULL)
	{
		this->open(name, mode);
	}

	template <class char_type>
	bool basic_source_file<char_type>::open(std::basic_string<char_type> const & name, open_mode mode){
		if (impl_ != NULL)
			return false;
		impl_ = new detail::ReadDeviceImpl();
		if(!detail::source_file_impl::open<char_type>(impl_->handle(), name, detail::source_file_impl::mode(mode))){
			delete impl_; impl_ = NULL;
			return false;
		}
		return true;
	}

	template <class char_type>
	void basic_source_file<char_type>::close(){
		if (impl_ != NULL) {
			detail::source_file_impl::close<char_type>(impl_->handle());
			delete impl_; impl_ = NULL;
		}
	}

	template <class char_type>
	std::streamsize basic_source_file<char_type>::read(char * buf, std::streamsize n){
		if (impl_ != NULL)
			return detail::source_file_impl::read<char_type>(impl_->handle(), buf, n);
		return -1;
	}

	template <class char_type>
	offset_type basic_source_file<char_type>::seek(offset_type where){
		if (impl_ != NULL)
			return detail::source_file_impl::seek<offset_type, char_type>(impl_->handle(), detail::source_file_impl::offset(where));
		return -1;
	}

	template <class char_type>
	offset_type basic_source_file<char_type>::seek(seek_dir way) {
		if (impl_ != NULL) {
			switch (way) {
				case beg : 
					return detail::source_file_impl::seek_beg<offset_type, char_type>(impl_->handle());
				case end : 
					return detail::source_file_impl::seek_end<offset_type, char_type>(impl_->handle());
				case cur : 
					return detail::source_file_impl::seek_cur<offset_type, char_type>(impl_->handle());
			}
		}
		return -1;
	}

	template class basic_source_file<char>;
	template class basic_source_file<wchar_t>;
}